import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import _toArray from "@babel/runtime/helpers/esm/toArray";
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import _extends from "@babel/runtime/helpers/esm/extends";
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
import _typeof from "@babel/runtime/helpers/esm/typeof";
import { createVNode as _createVNode } from "vue";
import DownOutlined from "@ant-design/icons-vue/es/icons/DownOutlined";
import { INTERNAL_COL_DEFINE } from '../../vc-table';
import { arrAdd, arrDel } from '../../vc-tree/util';
import { conductCheck } from '../../vc-tree/utils/conductUtil';
import { convertDataToEntities } from '../../vc-tree/utils/treeUtil';
import devWarning from '../../vc-util/devWarning';
import useMergedState from '../../_util/hooks/useMergedState';
import useState from '../../_util/hooks/useState';
import { watchEffect, computed, shallowRef } from 'vue';
import Checkbox from '../../checkbox';
import Dropdown from '../../dropdown';
import Menu from '../../menu';
import Radio from '../../radio';
import useMaxLevel from '../../vc-tree/useMaxLevel'; // TODO: warning if use ajax!!!

export var SELECTION_COLUMN = {};
export var SELECTION_ALL = 'SELECT_ALL';
export var SELECTION_INVERT = 'SELECT_INVERT';
export var SELECTION_NONE = 'SELECT_NONE';
var EMPTY_LIST = [];

function flattenData(data, childrenColumnName) {
  var list = [];
  (data || []).forEach(function (record) {
    list.push(record);

    if (record && _typeof(record) === 'object' && childrenColumnName in record) {
      list = [].concat(_toConsumableArray(list), _toConsumableArray(flattenData(record[childrenColumnName], childrenColumnName)));
    }
  });
  return list;
}

export default function useSelection(rowSelectionRef, configRef) {
  var mergedRowSelection = computed(function () {
    var temp = rowSelectionRef.value || {};
    var _temp$checkStrictly = temp.checkStrictly,
        checkStrictly = _temp$checkStrictly === void 0 ? true : _temp$checkStrictly;
    return _extends(_extends({}, temp), {
      checkStrictly: checkStrictly
    });
  }); // ========================= Keys =========================

  var _useMergedState = useMergedState(mergedRowSelection.value.selectedRowKeys || mergedRowSelection.value.defaultSelectedRowKeys || EMPTY_LIST, {
    value: computed(function () {
      return mergedRowSelection.value.selectedRowKeys;
    })
  }),
      _useMergedState2 = _slicedToArray(_useMergedState, 2),
      mergedSelectedKeys = _useMergedState2[0],
      setMergedSelectedKeys = _useMergedState2[1]; // ======================== Caches ========================


  var preserveRecordsRef = shallowRef(new Map());

  var updatePreserveRecordsCache = function updatePreserveRecordsCache(keys) {
    if (mergedRowSelection.value.preserveSelectedRowKeys) {
      var newCache = new Map(); // Keep key if mark as preserveSelectedRowKeys

      keys.forEach(function (key) {
        var record = configRef.getRecordByKey(key);

        if (!record && preserveRecordsRef.value.has(key)) {
          record = preserveRecordsRef.value.get(key);
        }

        newCache.set(key, record);
      }); // Refresh to new cache

      preserveRecordsRef.value = newCache;
    }
  };

  watchEffect(function () {
    updatePreserveRecordsCache(mergedSelectedKeys.value);
  });
  var keyEntities = computed(function () {
    return mergedRowSelection.value.checkStrictly ? null : convertDataToEntities(configRef.data.value, {
      externalGetKey: configRef.getRowKey.value,
      childrenPropName: configRef.childrenColumnName.value
    }).keyEntities;
  }); // Get flatten data

  var flattedData = computed(function () {
    return flattenData(configRef.pageData.value, configRef.childrenColumnName.value);
  }); // Get all checkbox props

  var checkboxPropsMap = computed(function () {
    var map = new Map();
    var getRowKey = configRef.getRowKey.value;
    var getCheckboxProps = mergedRowSelection.value.getCheckboxProps;
    flattedData.value.forEach(function (record, index) {
      var key = getRowKey(record, index);
      var checkboxProps = (getCheckboxProps ? getCheckboxProps(record) : null) || {};
      map.set(key, checkboxProps);

      if (process.env.NODE_ENV !== 'production' && ('checked' in checkboxProps || 'defaultChecked' in checkboxProps)) {
        devWarning(false, 'Table', 'Do not set `checked` or `defaultChecked` in `getCheckboxProps`. Please use `selectedRowKeys` instead.');
      }
    });
    return map;
  });

  var _useMaxLevel = useMaxLevel(keyEntities),
      maxLevel = _useMaxLevel.maxLevel,
      levelEntities = _useMaxLevel.levelEntities;

  var isCheckboxDisabled = function isCheckboxDisabled(r) {
    var _a;

    return !!((_a = checkboxPropsMap.value.get(configRef.getRowKey.value(r))) === null || _a === void 0 ? void 0 : _a.disabled);
  };

  var selectKeysState = computed(function () {
    if (mergedRowSelection.value.checkStrictly) {
      return [mergedSelectedKeys.value || [], []];
    }

    var _conductCheck = conductCheck(mergedSelectedKeys.value, true, keyEntities.value, maxLevel.value, levelEntities.value, isCheckboxDisabled),
        checkedKeys = _conductCheck.checkedKeys,
        halfCheckedKeys = _conductCheck.halfCheckedKeys;

    return [checkedKeys || [], halfCheckedKeys];
  });
  var derivedSelectedKeys = computed(function () {
    return selectKeysState.value[0];
  });
  var derivedHalfSelectedKeys = computed(function () {
    return selectKeysState.value[1];
  });
  var derivedSelectedKeySet = computed(function () {
    var keys = mergedRowSelection.value.type === 'radio' ? derivedSelectedKeys.value.slice(0, 1) : derivedSelectedKeys.value;
    return new Set(keys);
  });
  var derivedHalfSelectedKeySet = computed(function () {
    return mergedRowSelection.value.type === 'radio' ? new Set() : new Set(derivedHalfSelectedKeys.value);
  }); // Save last selected key to enable range selection

  var _useState = useState(null),
      _useState2 = _slicedToArray(_useState, 2),
      lastSelectedKey = _useState2[0],
      setLastSelectedKey = _useState2[1]; // // Reset if rowSelection reset
  // we use computed to reset, donot need setMergedSelectedKeys again like react
  // https://github.com/vueComponent/ant-design-vue/issues/4885
  // watchEffect(() => {
  //   if (!rowSelectionRef.value) {
  //     setMergedSelectedKeys([]);
  //   }
  // });


  var setSelectedKeys = function setSelectedKeys(keys) {
    var availableKeys;
    var records;
    updatePreserveRecordsCache(keys);
    var _mergedRowSelection$v = mergedRowSelection.value,
        preserveSelectedRowKeys = _mergedRowSelection$v.preserveSelectedRowKeys,
        onSelectionChange = _mergedRowSelection$v.onChange;
    var getRecordByKey = configRef.getRecordByKey;

    if (preserveSelectedRowKeys) {
      availableKeys = keys;
      records = keys.map(function (key) {
        return preserveRecordsRef.value.get(key);
      });
    } else {
      // Filter key which not exist in the `dataSource`
      availableKeys = [];
      records = [];
      keys.forEach(function (key) {
        var record = getRecordByKey(key);

        if (record !== undefined) {
          availableKeys.push(key);
          records.push(record);
        }
      });
    }

    setMergedSelectedKeys(availableKeys);
    onSelectionChange === null || onSelectionChange === void 0 ? void 0 : onSelectionChange(availableKeys, records);
  }; // ====================== Selections ======================
  // Trigger single `onSelect` event


  var triggerSingleSelection = function triggerSingleSelection(key, selected, keys, event) {
    var onSelect = mergedRowSelection.value.onSelect;

    var _ref = configRef || {},
        getRecordByKey = _ref.getRecordByKey;

    if (onSelect) {
      var rows = keys.map(function (k) {
        return getRecordByKey(k);
      });
      onSelect(getRecordByKey(key), selected, rows, event);
    }

    setSelectedKeys(keys);
  };

  var mergedSelections = computed(function () {
    var _mergedRowSelection$v2 = mergedRowSelection.value,
        onSelectInvert = _mergedRowSelection$v2.onSelectInvert,
        onSelectNone = _mergedRowSelection$v2.onSelectNone,
        selections = _mergedRowSelection$v2.selections,
        hideSelectAll = _mergedRowSelection$v2.hideSelectAll;
    var data = configRef.data,
        pageData = configRef.pageData,
        getRowKey = configRef.getRowKey,
        tableLocale = configRef.locale;

    if (!selections || hideSelectAll) {
      return null;
    }

    var selectionList = selections === true ? [SELECTION_ALL, SELECTION_INVERT, SELECTION_NONE] : selections;
    return selectionList.map(function (selection) {
      if (selection === SELECTION_ALL) {
        return {
          key: 'all',
          text: tableLocale.value.selectionAll,
          onSelect: function onSelect() {
            setSelectedKeys(data.value.map(function (record, index) {
              return getRowKey.value(record, index);
            }).filter(function (key) {
              var checkProps = checkboxPropsMap.value.get(key);
              return !(checkProps === null || checkProps === void 0 ? void 0 : checkProps.disabled) || derivedSelectedKeySet.value.has(key);
            }));
          }
        };
      }

      if (selection === SELECTION_INVERT) {
        return {
          key: 'invert',
          text: tableLocale.value.selectInvert,
          onSelect: function onSelect() {
            var keySet = new Set(derivedSelectedKeySet.value);
            pageData.value.forEach(function (record, index) {
              var key = getRowKey.value(record, index);
              var checkProps = checkboxPropsMap.value.get(key);

              if (!(checkProps === null || checkProps === void 0 ? void 0 : checkProps.disabled)) {
                if (keySet.has(key)) {
                  keySet.delete(key);
                } else {
                  keySet.add(key);
                }
              }
            });
            var keys = Array.from(keySet);

            if (onSelectInvert) {
              devWarning(false, 'Table', '`onSelectInvert` will be removed in future. Please use `onChange` instead.');
              onSelectInvert(keys);
            }

            setSelectedKeys(keys);
          }
        };
      }

      if (selection === SELECTION_NONE) {
        return {
          key: 'none',
          text: tableLocale.value.selectNone,
          onSelect: function onSelect() {
            onSelectNone === null || onSelectNone === void 0 ? void 0 : onSelectNone();
            setSelectedKeys(Array.from(derivedSelectedKeySet.value).filter(function (key) {
              var checkProps = checkboxPropsMap.value.get(key);
              return checkProps === null || checkProps === void 0 ? void 0 : checkProps.disabled;
            }));
          }
        };
      }

      return selection;
    });
  });
  var flattedDataLength = computed(function () {
    return flattedData.value.length;
  }); // ======================= Columns ========================

  var transformColumns = function transformColumns(columns) {
    var _a;

    var _mergedRowSelection$v3 = mergedRowSelection.value,
        onSelectAll = _mergedRowSelection$v3.onSelectAll,
        onSelectMultiple = _mergedRowSelection$v3.onSelectMultiple,
        selectionColWidth = _mergedRowSelection$v3.columnWidth,
        selectionType = _mergedRowSelection$v3.type,
        fixed = _mergedRowSelection$v3.fixed,
        customizeRenderCell = _mergedRowSelection$v3.renderCell,
        hideSelectAll = _mergedRowSelection$v3.hideSelectAll,
        checkStrictly = _mergedRowSelection$v3.checkStrictly;
    var prefixCls = configRef.prefixCls,
        getRecordByKey = configRef.getRecordByKey,
        getRowKey = configRef.getRowKey,
        expandType = configRef.expandType,
        getPopupContainer = configRef.getPopupContainer;

    if (!rowSelectionRef.value) {
      if (process.env.NODE_ENV !== 'production') {
        devWarning(!columns.includes(SELECTION_COLUMN), 'Table', '`rowSelection` is not config but `SELECTION_COLUMN` exists in the `columns`.');
      }

      return columns.filter(function (col) {
        return col !== SELECTION_COLUMN;
      });
    } // Support selection


    var cloneColumns = columns.slice();
    var keySet = new Set(derivedSelectedKeySet.value); // Record key only need check with enabled

    var recordKeys = flattedData.value.map(getRowKey.value).filter(function (key) {
      return !checkboxPropsMap.value.get(key).disabled;
    });
    var checkedCurrentAll = recordKeys.every(function (key) {
      return keySet.has(key);
    });
    var checkedCurrentSome = recordKeys.some(function (key) {
      return keySet.has(key);
    });

    var onSelectAllChange = function onSelectAllChange() {
      var changeKeys = [];

      if (checkedCurrentAll) {
        recordKeys.forEach(function (key) {
          keySet.delete(key);
          changeKeys.push(key);
        });
      } else {
        recordKeys.forEach(function (key) {
          if (!keySet.has(key)) {
            keySet.add(key);
            changeKeys.push(key);
          }
        });
      }

      var keys = Array.from(keySet);
      onSelectAll === null || onSelectAll === void 0 ? void 0 : onSelectAll(!checkedCurrentAll, keys.map(function (k) {
        return getRecordByKey(k);
      }), changeKeys.map(function (k) {
        return getRecordByKey(k);
      }));
      setSelectedKeys(keys);
    }; // ===================== Render =====================
    // Title Cell


    var title;

    if (selectionType !== 'radio') {
      var customizeSelections;

      if (mergedSelections.value) {
        var menu = _createVNode(Menu, {
          "getPopupContainer": getPopupContainer.value
        }, {
          default: function _default() {
            return [mergedSelections.value.map(function (selection, index) {
              var key = selection.key,
                  text = selection.text,
                  onSelectionClick = selection.onSelect;
              return _createVNode(Menu.Item, {
                "key": key || index,
                "onClick": function onClick() {
                  onSelectionClick === null || onSelectionClick === void 0 ? void 0 : onSelectionClick(recordKeys);
                }
              }, {
                default: function _default() {
                  return [text];
                }
              });
            })];
          }
        });

        customizeSelections = _createVNode("div", {
          "class": "".concat(prefixCls.value, "-selection-extra")
        }, [_createVNode(Dropdown, {
          "overlay": menu,
          "getPopupContainer": getPopupContainer.value
        }, {
          default: function _default() {
            return [_createVNode("span", null, [_createVNode(DownOutlined, null, null)])];
          }
        })]);
      }

      var allDisabledData = flattedData.value.map(function (record, index) {
        var key = getRowKey.value(record, index);
        var checkboxProps = checkboxPropsMap.value.get(key) || {};
        return _extends({
          checked: keySet.has(key)
        }, checkboxProps);
      }).filter(function (_ref2) {
        var disabled = _ref2.disabled;
        return disabled;
      });
      var allDisabled = !!allDisabledData.length && allDisabledData.length === flattedDataLength.value;
      var allDisabledAndChecked = allDisabled && allDisabledData.every(function (_ref3) {
        var checked = _ref3.checked;
        return checked;
      });
      var allDisabledSomeChecked = allDisabled && allDisabledData.some(function (_ref4) {
        var checked = _ref4.checked;
        return checked;
      });
      title = !hideSelectAll && _createVNode("div", {
        "class": "".concat(prefixCls.value, "-selection")
      }, [_createVNode(Checkbox, {
        "checked": !allDisabled ? !!flattedDataLength.value && checkedCurrentAll : allDisabledAndChecked,
        "indeterminate": !allDisabled ? !checkedCurrentAll && checkedCurrentSome : !allDisabledAndChecked && allDisabledSomeChecked,
        "onChange": onSelectAllChange,
        "disabled": flattedDataLength.value === 0 || allDisabled,
        "skipGroup": true
      }, null), customizeSelections]);
    } // Body Cell


    var renderCell;

    if (selectionType === 'radio') {
      renderCell = function renderCell(_ref5) {
        var record = _ref5.record,
            index = _ref5.index;
        var key = getRowKey.value(record, index);
        var checked = keySet.has(key);
        return {
          node: _createVNode(Radio, _objectSpread(_objectSpread({}, checkboxPropsMap.value.get(key)), {}, {
            "checked": checked,
            "onClick": function onClick(e) {
              return e.stopPropagation();
            },
            "onChange": function onChange(event) {
              if (!keySet.has(key)) {
                triggerSingleSelection(key, true, [key], event.nativeEvent);
              }
            }
          }), null),
          checked: checked
        };
      };
    } else {
      renderCell = function renderCell(_ref6) {
        var record = _ref6.record,
            index = _ref6.index;

        var _a;

        var key = getRowKey.value(record, index);
        var checked = keySet.has(key);
        var indeterminate = derivedHalfSelectedKeySet.value.has(key);
        var checkboxProps = checkboxPropsMap.value.get(key);
        var mergedIndeterminate;

        if (expandType.value === 'nest') {
          mergedIndeterminate = indeterminate;
          devWarning(typeof (checkboxProps === null || checkboxProps === void 0 ? void 0 : checkboxProps.indeterminate) !== 'boolean', 'Table', 'set `indeterminate` using `rowSelection.getCheckboxProps` is not allowed with tree structured dataSource.');
        } else {
          mergedIndeterminate = (_a = checkboxProps === null || checkboxProps === void 0 ? void 0 : checkboxProps.indeterminate) !== null && _a !== void 0 ? _a : indeterminate;
        } // Record checked


        return {
          node: _createVNode(Checkbox, _objectSpread(_objectSpread({}, checkboxProps), {}, {
            "indeterminate": mergedIndeterminate,
            "checked": checked,
            "skipGroup": true,
            "onClick": function onClick(e) {
              return e.stopPropagation();
            },
            "onChange": function onChange(_ref7) {
              var nativeEvent = _ref7.nativeEvent;
              var shiftKey = nativeEvent.shiftKey;
              var startIndex = -1;
              var endIndex = -1; // Get range of this

              if (shiftKey && checkStrictly) {
                var pointKeys = new Set([lastSelectedKey.value, key]);
                recordKeys.some(function (recordKey, recordIndex) {
                  if (pointKeys.has(recordKey)) {
                    if (startIndex === -1) {
                      startIndex = recordIndex;
                    } else {
                      endIndex = recordIndex;
                      return true;
                    }
                  }

                  return false;
                });
              }

              if (endIndex !== -1 && startIndex !== endIndex && checkStrictly) {
                // Batch update selections
                var rangeKeys = recordKeys.slice(startIndex, endIndex + 1);
                var changedKeys = [];

                if (checked) {
                  rangeKeys.forEach(function (recordKey) {
                    if (keySet.has(recordKey)) {
                      changedKeys.push(recordKey);
                      keySet.delete(recordKey);
                    }
                  });
                } else {
                  rangeKeys.forEach(function (recordKey) {
                    if (!keySet.has(recordKey)) {
                      changedKeys.push(recordKey);
                      keySet.add(recordKey);
                    }
                  });
                }

                var keys = Array.from(keySet);
                onSelectMultiple === null || onSelectMultiple === void 0 ? void 0 : onSelectMultiple(!checked, keys.map(function (recordKey) {
                  return getRecordByKey(recordKey);
                }), changedKeys.map(function (recordKey) {
                  return getRecordByKey(recordKey);
                }));
                setSelectedKeys(keys);
              } else {
                // Single record selected
                var originCheckedKeys = derivedSelectedKeys.value;

                if (checkStrictly) {
                  var checkedKeys = checked ? arrDel(originCheckedKeys, key) : arrAdd(originCheckedKeys, key);
                  triggerSingleSelection(key, !checked, checkedKeys, nativeEvent);
                } else {
                  // Always fill first
                  var result = conductCheck([].concat(_toConsumableArray(originCheckedKeys), [key]), true, keyEntities.value, maxLevel.value, levelEntities.value, isCheckboxDisabled);
                  var _checkedKeys = result.checkedKeys,
                      halfCheckedKeys = result.halfCheckedKeys;
                  var nextCheckedKeys = _checkedKeys; // If remove, we do it again to correction

                  if (checked) {
                    var tempKeySet = new Set(_checkedKeys);
                    tempKeySet.delete(key);
                    nextCheckedKeys = conductCheck(Array.from(tempKeySet), {
                      checked: false,
                      halfCheckedKeys: halfCheckedKeys
                    }, keyEntities.value, maxLevel.value, levelEntities.value, isCheckboxDisabled).checkedKeys;
                  }

                  triggerSingleSelection(key, !checked, nextCheckedKeys, nativeEvent);
                }
              }

              setLastSelectedKey(key);
            }
          }), null),
          checked: checked
        };
      };
    }

    var renderSelectionCell = function renderSelectionCell(_ref8) {
      var record = _ref8.record,
          index = _ref8.index;

      var _renderCell = renderCell({
        record: record,
        index: index
      }),
          node = _renderCell.node,
          checked = _renderCell.checked;

      if (customizeRenderCell) {
        return customizeRenderCell(checked, record, index, node);
      }

      return node;
    }; // Insert selection column if not exist


    if (!cloneColumns.includes(SELECTION_COLUMN)) {
      // Always after expand icon
      if (cloneColumns.findIndex(function (col) {
        var _a;

        return ((_a = col[INTERNAL_COL_DEFINE]) === null || _a === void 0 ? void 0 : _a.columnType) === 'EXPAND_COLUMN';
      }) === 0) {
        var _cloneColumns = cloneColumns,
            _cloneColumns2 = _toArray(_cloneColumns),
            expandColumn = _cloneColumns2[0],
            restColumns = _cloneColumns2.slice(1);

        cloneColumns = [expandColumn, SELECTION_COLUMN].concat(_toConsumableArray(restColumns));
      } else {
        // Normal insert at first column
        cloneColumns = [SELECTION_COLUMN].concat(_toConsumableArray(cloneColumns));
      }
    } // Deduplicate selection column


    var selectionColumnIndex = cloneColumns.indexOf(SELECTION_COLUMN);

    if (process.env.NODE_ENV !== 'production' && cloneColumns.filter(function (col) {
      return col === SELECTION_COLUMN;
    }).length > 1) {
      devWarning(false, 'Table', 'Multiple `SELECTION_COLUMN` exist in `columns`.');
    }

    cloneColumns = cloneColumns.filter(function (column, index) {
      return column !== SELECTION_COLUMN || index === selectionColumnIndex;
    }); // Fixed column logic

    var prevCol = cloneColumns[selectionColumnIndex - 1];
    var nextCol = cloneColumns[selectionColumnIndex + 1];
    var mergedFixed = fixed;

    if (mergedFixed === undefined) {
      if ((nextCol === null || nextCol === void 0 ? void 0 : nextCol.fixed) !== undefined) {
        mergedFixed = nextCol.fixed;
      } else if ((prevCol === null || prevCol === void 0 ? void 0 : prevCol.fixed) !== undefined) {
        mergedFixed = prevCol.fixed;
      }
    }

    if (mergedFixed && prevCol && ((_a = prevCol[INTERNAL_COL_DEFINE]) === null || _a === void 0 ? void 0 : _a.columnType) === 'EXPAND_COLUMN' && prevCol.fixed === undefined) {
      prevCol.fixed = mergedFixed;
    } // Replace with real selection column


    var selectionColumn = _defineProperty({
      fixed: mergedFixed,
      width: selectionColWidth,
      className: "".concat(prefixCls.value, "-selection-column"),
      title: mergedRowSelection.value.columnTitle || title,
      customRender: renderSelectionCell
    }, INTERNAL_COL_DEFINE, {
      class: "".concat(prefixCls.value, "-selection-col")
    });

    return cloneColumns.map(function (col) {
      return col === SELECTION_COLUMN ? selectionColumn : col;
    });
  };

  return [transformColumns, derivedSelectedKeySet];
}